//
// Created by DELL on 2023/8/15.
//
#include <iostream>
#include <Windows.h>
#include <Dbghelp.h>
#include <thread>
#pragma comment(lib, "Dbghelp.lib")

void createMinidump()
{
    wchar_t DumpPath[MAX_PATH] = {0};

    SYSTEMTIME SystemTime;
    GetLocalTime(&SystemTime);

    WCHAR szExeFileName[256] = {0};
    GetModuleFileNameW(nullptr, szExeFileName, 99);

    wsprintfW(DumpPath, L"%s_%d-%d-%d_%d-%d-%d.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth,
              SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);

    HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);

    if (file != INVALID_HANDLE_VALUE)
    {
        DWORD Flags = MiniDumpWithHandleData |
                      MiniDumpWithUnloadedModules |
                      MiniDumpScanMemory|
                      MiniDumpWithIndirectlyReferencedMemory |
                      MiniDumpWithProcessThreadData |
                      MiniDumpWithThreadInfo;

        if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD) GetCurrentProcessId(), file,
                              (MINIDUMP_TYPE) (Flags),
                              nullptr, nullptr, nullptr) != 0)
        {
            std::cout << "Create Minidump successful!! file:";
            std::wcout << DumpPath << std::endl;
        }
        else
        {
            std::cout << "Create Minidump failed!!" << std::endl;
        }
    }

    CloseHandle(file);
}

void createFullDump()
{
    wchar_t DumpPath[MAX_PATH] = {0};

    SYSTEMTIME SystemTime;
    GetLocalTime(&SystemTime);

    WCHAR szExeFileName[256] = {0};
    GetModuleFileNameW(nullptr, szExeFileName, 99);

    wsprintfW(DumpPath, L"%s_%d-%d-%d_%d-%d-%d_full.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth,
              SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);

    HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);

    if (file != INVALID_HANDLE_VALUE)
    {

        const DWORD Flags = MiniDumpWithFullMemory |
                            MiniDumpWithFullMemoryInfo |
                            MiniDumpWithHandleData |
                            MiniDumpWithUnloadedModules |
                            MiniDumpWithProcessThreadData |
                            MiniDumpWithThreadInfo;

        if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD) GetCurrentProcessId(), file,
                              (MINIDUMP_TYPE) (Flags),
                              nullptr, nullptr, nullptr) != 0)
        {
            std::cout << "Create Full dump successful!! file:";
            std::wcout << DumpPath << std::endl;
        }
        else
        {
            std::cout << "Create Full dump failed!!" << std::endl;
        }
    }

    CloseHandle(file);
}

LONG WINAPI DumpException(EXCEPTION_POINTERS* info)
{
    std::cout << "DumpException, Thread ID:"<< std::this_thread::get_id() << std::endl;
    std::cout << "Exception: 0x" << std::hex << info->ExceptionRecord->ExceptionCode << std::endl;

    wchar_t DumpPath[MAX_PATH] = { 0 };

    SYSTEMTIME SystemTime;
    GetLocalTime(&SystemTime);

    WCHAR szExeFileName[100] = { 0 };
    GetModuleFileNameW(nullptr, szExeFileName, 99);

    wsprintfW(DumpPath, L"%s_%d-%d-%d_%d-%d-%d_crash.dmp", szExeFileName, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);

    HANDLE file = CreateFileW(DumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    if (file != INVALID_HANDLE_VALUE)
    {
        MINIDUMP_EXCEPTION_INFORMATION mdei;
        mdei.ThreadId = (DWORD)GetCurrentThreadId();
        mdei.ExceptionPointers = info;
        mdei.ClientPointers = 0;

        DWORD Flags = MiniDumpWithHandleData |
                      MiniDumpWithUnloadedModules |
                      MiniDumpScanMemory|
                      MiniDumpWithIndirectlyReferencedMemory |
                      MiniDumpWithProcessThreadData |
                      MiniDumpWithThreadInfo;

//        Flags = MiniDumpWithFullMemory |
//                MiniDumpWithFullMemoryInfo |
//                MiniDumpWithHandleData |
//                MiniDumpWithUnloadedModules |
//                MiniDumpWithThreadInfo;

        if (MiniDumpWriteDump(GetCurrentProcess(), (DWORD)GetCurrentProcessId(), file,
                              (MINIDUMP_TYPE)(Flags),
                              &mdei, nullptr, nullptr) != 0)
        {
            std::cout << "Create Crash dump successful!! file:";
            std::wcout << DumpPath << std::endl;
            CloseHandle(file);
            return EXCEPTION_EXECUTE_HANDLER;
        }
    }
    std::cout << "Create Crash dump failed!!" << std::endl;
    CloseHandle(file);

    return EXCEPTION_CONTINUE_SEARCH;
}
